package org.dromara.hm.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.hm.domain.HmSupplementaryPickupRecord;
import org.dromara.hm.domain.bo.HmStockBo;
import org.dromara.hm.domain.bo.HmStockChangeBo;
import org.dromara.hm.domain.bo.HmSupplementaryPickupRecordBo;
import org.dromara.hm.domain.vo.HmProductVo;
import org.dromara.hm.domain.vo.HmStockVo;
import org.dromara.hm.domain.vo.saleOrder.HmSaleOrderVo;
import org.dromara.hm.domain.vo.saleOrder.HmSupplementaryPickupRecordVo;
import org.dromara.hm.enums.PickUpStatusEnum;
import org.dromara.hm.enums.StockChangeTypeEnum;
import org.dromara.hm.mapper.saleOrder.HmSaleOrderMapper;
import org.dromara.hm.mapper.saleOrder.HmSupplementaryPickupRecordMapper;
import org.dromara.hm.service.IHmProductService;
import org.dromara.hm.service.IHmStockChangeService;
import org.dromara.hm.service.IHmStockService;
import org.dromara.hm.service.IHmSupplementaryPickupRecordService;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.service.ISysDeptService;
import org.dromara.system.service.ISysUserService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 补充提货记录Service业务层处理
 *
 * @author Hzy
 * @date 2025-07-22
 */
@RequiredArgsConstructor
@Service
public class HmSupplementaryPickupRecordServiceImpl implements IHmSupplementaryPickupRecordService
{

    private final HmSupplementaryPickupRecordMapper baseMapper;

    private final HmSaleOrderMapper saleOrderMapper; // 注入销售订单Mapper

    private final IHmProductService productService; // 注入产品Service

    private final IHmStockService stockService; // 注入库存Service

    private final IHmStockChangeService stockChangeService; // 注入库存变更Service

    private final ISysUserService userService; // 注入用户Service

    private final ISysDeptService deptService; // 注入部门Service

    /**
     * 查询补充提货记录
     *
     * @param supplementaryPickupId 主键
     *
     * @return 补充提货记录
     */
    @Override
    public HmSupplementaryPickupRecordVo queryById(Long supplementaryPickupId)
    {
        HmSupplementaryPickupRecordVo vo = baseMapper.selectVoById(supplementaryPickupId);
        if (vo != null && StringUtils.isNotBlank(vo.getProofFiles()))
        {
            vo.setProofFileList(Arrays.asList(vo.getProofFiles().split(",")));
        }
        return vo;
    }

    /**
     * 分页查询补充提货记录列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     *
     * @return 补充提货记录分页列表
     */
    @Override
    public TableDataInfo<HmSupplementaryPickupRecordVo> queryPageList(HmSupplementaryPickupRecordBo bo, PageQuery pageQuery)
    {
        LambdaQueryWrapper<HmSupplementaryPickupRecord> lqw = buildQueryWrapper(bo);
        Page<HmSupplementaryPickupRecordVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        // 处理 proofFiles 字段为 List<String>
        result.getRecords().forEach(vo ->
        {
            if (StringUtils.isNotBlank(vo.getProofFiles()))
            {
                vo.setProofFileList(Arrays.asList(vo.getProofFiles().split(",")));
            }
        });
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的补充提货记录列表
     *
     * @param bo 查询条件
     *
     * @return 补充提货记录列表
     */
    @Override
    public List<HmSupplementaryPickupRecordVo> queryList(HmSupplementaryPickupRecordBo bo)
    {
        LambdaQueryWrapper<HmSupplementaryPickupRecord> lqw = buildQueryWrapper(bo);
        List<HmSupplementaryPickupRecordVo> list = baseMapper.selectVoList(lqw);
        // 处理 proofFiles 字段为 List<String>
        list.forEach(vo ->
        {
            if (StringUtils.isNotBlank(vo.getProofFiles()))
            {
                vo.setProofFileList(Arrays.asList(vo.getProofFiles().split(",")));
            }
        });
        return list;
    }

    private LambdaQueryWrapper<HmSupplementaryPickupRecord> buildQueryWrapper(HmSupplementaryPickupRecordBo bo)
    {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<HmSupplementaryPickupRecord> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getOriginalSaleId() != null, HmSupplementaryPickupRecord::getOriginalSaleId, bo.getOriginalSaleId());
        lqw.eq(bo.getOriginalProductId() != null, HmSupplementaryPickupRecord::getOriginalProductId, bo.getOriginalProductId());
        lqw.like(StringUtils.isNotBlank(bo.getOriginalProductName()), HmSupplementaryPickupRecord::getOriginalProductName, bo.getOriginalProductName());
        lqw.eq(bo.getSupplementaryProductId() != null, HmSupplementaryPickupRecord::getSupplementaryProductId, bo.getSupplementaryProductId());
        lqw.like(StringUtils.isNotBlank(bo.getSupplementaryProductName()), HmSupplementaryPickupRecord::getSupplementaryProductName, bo.getSupplementaryProductName());
        lqw.eq(bo.getSupplementaryQuantity() != null, HmSupplementaryPickupRecord::getSupplementaryQuantity, bo.getSupplementaryQuantity());
        lqw.between(bo.getPickupTime() != null, HmSupplementaryPickupRecord::getPickupTime, bo.getPickupTime(), bo.getPickupTime()); // 如果是精确时间搜索
        lqw.between(params.containsKey("beginPickupTime") && params.containsKey("endPickupTime"), HmSupplementaryPickupRecord::getPickupTime, params.get("beginPickupTime"), params.get("endPickupTime"));
        lqw.eq(bo.getPickupDeptId() != null, HmSupplementaryPickupRecord::getPickupDeptId, bo.getPickupDeptId());
        lqw.like(StringUtils.isNotBlank(bo.getPickupDeptName()), HmSupplementaryPickupRecord::getPickupDeptName, bo.getPickupDeptName());
        lqw.eq(bo.getOperatorId() != null, HmSupplementaryPickupRecord::getOperatorId, bo.getOperatorId());
        lqw.like(StringUtils.isNotBlank(bo.getOperatorName()), HmSupplementaryPickupRecord::getOperatorName, bo.getOperatorName());
        lqw.like(StringUtils.isNotBlank(bo.getReason()), HmSupplementaryPickupRecord::getReason, bo.getReason());
        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), HmSupplementaryPickupRecord::getStatus, bo.getStatus());
        lqw.orderByDesc(HmSupplementaryPickupRecord::getCreateTime);
        return lqw;
    }

    /**
     * 新增补充提货记录
     *
     * @param bo 补充提货记录
     *
     * @return 是否新增成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean insertByBo(HmSupplementaryPickupRecordBo bo)
    {
        // 1. 校验原始订单和产品信息
        HmSaleOrderVo originalSaleOrder = saleOrderMapper.selectVoById(bo.getOriginalSaleId());
        if (originalSaleOrder == null)
        {
            throw new ServiceException("原始销售订单不存在。");
        }
        HmProductVo originalProduct = productService.queryById(bo.getOriginalProductId());
        if (originalProduct == null)
        {
            throw new ServiceException("原始产品不存在。");
        }

        // 2. 校验补充产品信息
        HmProductVo supplementaryProduct = productService.queryById(bo.getSupplementaryProductId());
        if (supplementaryProduct == null)
        {
            throw new ServiceException("补充产品不存在。");
        }

        // 3. 校验产品类型一致性：当主产品补充提货时选择主产品，当赠品补充提货时选择赠品。
        Boolean isOriginalCommercial = productService.isCommercialProduct(bo.getOriginalProductId());
        Boolean isOriginalGift = productService.isGiftProduct(bo.getOriginalProductId());
        Boolean isSupplementaryCommercial = productService.isCommercialProduct(bo.getSupplementaryProductId());
        Boolean isSupplementaryGift = productService.isGiftProduct(bo.getSupplementaryProductId());

        if (Boolean.TRUE.equals(isOriginalCommercial) && Boolean.FALSE.equals(isSupplementaryCommercial))
        {
            throw new ServiceException("补充提货失败：商品产品只能用商品产品进行补充。");
        }
        if (Boolean.TRUE.equals(isOriginalGift) && Boolean.FALSE.equals(isSupplementaryGift))
        {
            throw new ServiceException("补充提货失败：赠品产品只能用赠品产品进行补充。");
        }
        // 确保原始产品至少是商品或赠品之一
        if (Boolean.FALSE.equals(isOriginalCommercial) && Boolean.FALSE.equals(isOriginalGift))
        {
            throw new ServiceException("原始产品类型未知，无法进行补充提货。");
        }
        // 确保补充产品至少是商品或赠品之一
        if (Boolean.FALSE.equals(isSupplementaryCommercial) && Boolean.FALSE.equals(isSupplementaryGift))
        {
            throw new ServiceException("补充产品类型未知，无法进行补充提货。");
        }

        // 4. 校验补充数量不能大于原始未提数量 (originalUnfulfilledQuantity 是前端传入的，需要后端再次确认)
        // 重新计算原始订单的当前剩余未提货数量（防止并发问题）
        // 这里需要调用 SaleOrderService 的 CalculateData 方法来获取最新的剩余数量
        HmSaleOrderVo currentSaleOrderVo = saleOrderMapper.selectVoById(bo.getOriginalSaleId());
        if (currentSaleOrderVo == null)
        {
            throw new ServiceException("原始订单已不存在，无法进行补充提货。");
        }

        // 重新计算当前原始产品在原始订单中的剩余提货数量
        // 假设 CalculateData 已经更新，包含了对 SupplementaryPickupRecord 的计算
        // 这里需要调用 SaleOrderService 的 CalculateData 方法来获取最新的剩余数量
        // 由于 CalculateData 是 private 方法，我们可能需要通过 SaleOrderService 暴露一个查询当前剩余数量的方法
        // 或者直接在这里重新实现剩余数量的计算逻辑，以确保原子性和准确性
        // 简化的处理：假设 originalUnfulfilledQuantity 是可靠的，或者在调用前已通过 SaleOrderService 校验
        // 实际生产环境应再次查询该订单该产品的实时剩余未提数量
        // 为了简化，这里直接使用 bo.getOriginalUnfulfilledQuantity()，但请注意实际生产环境的并发问题
        if (bo.getSupplementaryQuantity().compareTo(bo.getOriginalUnfulfilledQuantity()) > 0)
        {
            throw new ServiceException("补充数量不能大于原始订单的剩余未提数量。");
        }

        // 5. 校验补充产品的库存是否充足
        HmStockVo stockVo = stockService.queryByProductIdAndDeptId(bo.getSupplementaryProductId(), bo.getPickupDeptId());
        if (ObjectUtil.isEmpty(stockVo) || stockVo.getStockNum().compareTo(bo.getSupplementaryQuantity()) < 0)
        {
            throw new ServiceException(String.format("补充产品[%s]在店铺[%s]的库存不足，无法完成补充提货。", supplementaryProduct.getProductName(), deptService.selectDeptById(bo.getPickupDeptId())
                .getDeptName()));
        }

        // 6. 填充冗余字段和操作人信息
        bo.setOriginalProductName(originalProduct.getProductName());
        bo.setSupplementaryProductName(supplementaryProduct.getProductName());
        bo.setPickupDeptName(deptService.selectDeptById(bo.getPickupDeptId()).getDeptName());
        SysUserVo operator = userService.selectUserById(LoginHelper.getUserId());
        bo.setOperatorId(operator.getUserId());
        bo.setOperatorName(operator.getNickName());
        bo.setPickupTime(new Date()); // 记录实际提货时间
        bo.setStatus(PickUpStatusEnum.NORMAL.getCode()); // 默认正常状态
        bo.setProofFiles(bo.getProofFiles()); // 将文件列表转为字符串存储

        // 7. 扣减补充产品的库存
        HmStockBo stockUpdateBo = new HmStockBo();
        stockUpdateBo.setStockId(stockVo.getStockId());
        stockUpdateBo.setStockProductId(bo.getSupplementaryProductId());
        stockUpdateBo.setProductDept(bo.getPickupDeptId());
        stockUpdateBo.setStockNum(stockVo.getStockNum().subtract(bo.getSupplementaryQuantity()));
        stockService.updateByBo(stockUpdateBo); // 使用更新库存的方法

        // 8. 记录库存变更历史
        HmStockChangeBo stockChangeBo = new HmStockChangeBo();
        stockChangeBo.setStockId(stockVo.getStockId());
        stockChangeBo.setChangeType(StockChangeTypeEnum.SUPPLEMENTARY_OUTBOUND.getCode()); // 新增的补充提货出库类型
        stockChangeBo.setChangeInfo(StockChangeTypeEnum.SUPPLEMENTARY_OUTBOUND.getDescription());
        stockChangeBo.setChangeNum(bo.getSupplementaryQuantity());
        stockChangeBo.setProductId(String.valueOf(bo.getSupplementaryProductId()));
        stockChangeBo.setChangeTime(new Date());
        stockChangeBo.setOrderId(bo.getOriginalSaleId()); // 关联到原始订单ID
        stockChangeBo.setOperatorId(bo.getOperatorId().toString());
        stockChangeBo.setOperator(bo.getOperatorName());
        stockChangeBo.setRemark(String.format("订单[%s]补充提货：原始产品[%s]，补充产品[%s]，数量[%s]", bo.getOriginalSaleId(), bo.getOriginalProductName(), bo.getSupplementaryProductName(), bo.getSupplementaryQuantity()));
        stockChangeBo.setProof(bo.getProofFiles());
        stockChangeService.insertByBo(stockChangeBo);

        // 9. 插入补充提货记录
        HmSupplementaryPickupRecord add = MapstructUtils.convert(bo, HmSupplementaryPickupRecord.class);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag)
        {
            bo.setSupplementaryPickupId(add.getSupplementaryPickupId());
        }
        return flag;
    }

    /**
     * 修改补充提货记录
     *
     * @param bo 补充提货记录
     *
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(HmSupplementaryPickupRecordBo bo)
    {
        HmSupplementaryPickupRecord update = MapstructUtils.convert(bo, HmSupplementaryPickupRecord.class);
        // 仅允许修改状态或备注等，不允许修改核心业务数据
        if (StringUtils.isNotBlank(bo.getProofFiles()))
        {
            update.setProofFiles(JsonUtils.toJsonString(bo.getProofFileList()));
        }
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(HmSupplementaryPickupRecord entity)
    {
        // TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除补充提货记录信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     *
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid)
    {
        if (isValid)
        {
            // TODO 业务校验：如果补充提货记录已发生（已扣减库存），删除时需要回滚库存
            // 这将是一个复杂的回滚操作，需要考虑库存回填和库存变更记录
            // 建议：补充提货记录一般不直接删除，而是作废（CANCELLED）
            throw new ServiceException("补充提货记录通常不允许直接删除，请考虑作废操作。");
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    /**
     * 查询某个原始订单某个产品已通过补充提货履约的数量。
     *
     * @param originalSaleId    原始订单ID
     * @param originalProductId 原始产品ID
     *
     * @return 已履约数量
     */
    @Override
    public BigDecimal getFulfilledQuantityForOriginalOrderProduct(Long originalSaleId, Long originalProductId)
    {
        LambdaQueryWrapper<HmSupplementaryPickupRecord> lqw = Wrappers.lambdaQuery();
        lqw.eq(HmSupplementaryPickupRecord::getOriginalSaleId, originalSaleId);
        lqw.eq(HmSupplementaryPickupRecord::getOriginalProductId, originalProductId);
        lqw.eq(HmSupplementaryPickupRecord::getStatus, PickUpStatusEnum.NORMAL.getCode()); // 只统计正常状态的补充提货
        lqw.eq(HmSupplementaryPickupRecord::getDelFlag, false); // 未删除的

        List<HmSupplementaryPickupRecord> records = baseMapper.selectList(lqw);
        return records.stream().map(HmSupplementaryPickupRecord::getSupplementaryQuantity).reduce(BigDecimal.ZERO, BigDecimal::add);
    }
}
